package qc.module.platform.api.controller;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.*;
import qc.common.core.constants.QCAuthConstant;
import qc.common.core.enums.QCAuthValidateMethodEnum;
import qc.common.core.exception.QCPromptException;
import qc.common.core.exception.QcTokenInvalidException;
import qc.common.core.utils.StringSplitUtil;
import qc.module.platform.dto.uac.*;
import qc.module.platform.service.MenusService;
import qc.module.platform.service.UserAccessControlService;
import qc.module.platform.service.UserLoginLogService;

import javax.servlet.http.HttpServletRequest;
import java.util.List;

/**
 * 用户控制 Controller
 * 用于用户登录、退出、获取个人信息、获取权限控制及权限资源等操作
 *
 * @author QuCheng Tech
 * @create 2023/1/9
 */
@RestController
@RefreshScope
@RequestMapping("/uac")
public class UserAccessControlController {
    private UserAccessControlService uacService;

    private UserLoginLogService userLoginLogService;

    private MenusService menusService;

    /**
     * 小程序的appid，从nacos配置文件中获取，默认为wx6ac300316ca43f35
     */
    @Value("${qucheng.appid:wx6ac300316ca43f35}")
    private String APPID;

    /**
     * 用户登录失败判断的分钟数，判断本次登录前N分钟内的登录失败次数
     */
    @Value("${qucheng.uac.login.judgeminutes:30}")
    private int User_Login_Judge_Minutes;

    /**
     * 同一个用户最大允许登录失败次数，在User_Login_Judge_Minutes内最多允许失败n次，超过该次数不允许进行登录尝试
     */
    @Value("${qucheng.uac.login.attempttimes:5}")
    private int User_Login_Max_Attempt_Times;

    /**
     * 同一个IP地址用户登录失败次数超过n次，将IP地址加入黑名单并禁止在n小时内登录，从nacos配置文件中获取
     */
    @Value("${qucheng.uac.login.bl-times:30}")
    private int User_Login_Fail_Addto_BlackList_Max_Times;

    /**
     * 用户登录失败超过最大次数后加入黑名单限制登录的分钟数，默认为1天=1440min
     */
    @Value("${qucheng.uac.login.bl-minutes:1440}")
    private int User_Login_Fail_Addto_BlackList_Expired_Minutes;

    @Autowired
    public void setUserAccessControlService(UserAccessControlService service) {
        this.uacService = service;
    }

    @Autowired
    public void setUserLoginLogService(UserLoginLogService service) {
        this.userLoginLogService = service;
    }

    @Autowired
    public void setMenusService(MenusService menusService) {
        this.menusService = menusService;
    }

    @Autowired
    HttpServletRequest request;

    @Autowired
    private RestTemplateWeiXin restTemplateWeiXin;

    /**
     * 用户登录，返回登录结果
     *
     * @param dto 登录输入信息，包含登录验证方式、输入的登录名和密码
     * @return 登录结果中包含是否成功、用户名称、token和项目集合
     * @author QuCheng Tech
     * @since 2023/5/28
     */
    @RequestMapping(value = "/login", method = {RequestMethod.GET, RequestMethod.POST})
    public LoginResultDto login(@RequestBody LoginDto dto) throws QCPromptException {
        //客户端信息可以从request中获取
        String userAgent = request.getHeader(QCAuthConstant.USER_AGENT_HEADER_KEY);
        //获取访问客户端IP，可能有nginx等代理服务器无法获取客户端真实IP地址，需要进行判断处理        
        String ip = request.getHeader("X-FORWARDED-FOR");
        //2025-1-18，实测通过微信小程序调试工具得到的IP地址为：112.117.204.213,127.0.0.1
        System.out.println("Get ip From X-FORWARDED-FOR:" + ip);
        if (ip == null || ip.isEmpty() || StringUtils.equalsIgnoreCase(ip, "unknown")) {
            ip = request.getHeader("Proxy-Client-IP");
            System.out.println("Get ip From Proxy-Client-IP:" + ip);
        }
        if (ip == null || ip.isEmpty() || StringUtils.equalsIgnoreCase(ip, "unknown")) {
            ip = request.getHeader("WL-Proxy-Client-IP");
            System.out.println("Get ip From WL-Proxy-Client-IP:" + ip);
        }
        if (ip == null || ip.isEmpty() || StringUtils.equalsIgnoreCase(ip, "unknown")) {
            ip = request.getRemoteAddr();
            System.out.println("Get ip From request.getRemoteAddr:" + ip);
        }
        //需要根据IP地址进行分解，默认获取第一个
        if (StringUtils.isNotBlank(ip)) {
            String[] splitIps = StringSplitUtil.Split(ip, true);
            if (splitIps != null && splitIps.length > 0x0)
                ip = splitIps[0x0];
        }

        //权限验证需要token，获取token
        String token = request.getHeader(QCAuthConstant.TOKEN_HEADER_KEY);

        //根据客户端userAgent可以设置之前的登录记录为过期，避免历史token可重复使用问题
        //在Service中的login方法中进行统一处理；在向登录日志表中写入记录后对原有的登录记录设置token过期

        //判断如果是使用第三方验证，需要调用第三方提供的API接口获取手机号，在controller中调用对应接口后传入手机号给service
        QCAuthValidateMethodEnum validateMethod = QCAuthValidateMethodEnum.PWD;
        //获取身份验证方式，需要根据不同的验证方式进行判断；默认验证方式使用账号密码
        validateMethod = getQCAuthValidateMethodEnum(dto.getVtype());
        if (validateMethod == QCAuthValidateMethodEnum.THIRD) {
            //根据code调用微信用户接口中获取手机号，作为登录code
            String phone = restTemplateWeiXin.getPhoneByCode(APPID, dto.getCode());
            dto.setCode(phone);
        }

        return uacService.login(validateMethod, dto, userAgent, ip, token, User_Login_Judge_Minutes, User_Login_Max_Attempt_Times, User_Login_Fail_Addto_BlackList_Max_Times, User_Login_Fail_Addto_BlackList_Expired_Minutes);
    }

    /**
     * 获取用户信息，从请求头中的token获取
     *
     * @return 用户信息，包含ID、名称、手机号、项目编码
     * @author QuCheng Tech
     * @since 2023/5/28
     */
    @GetMapping("/userinfo")
    public UacUserInfoDto getUserInfo() throws QcTokenInvalidException {
        //权限验证需要token，获取token
        String token = request.getHeader(QCAuthConstant.TOKEN_HEADER_KEY);
        //如果在请求头中指定了当前项目编码，获取用户信息时固定使用该项目编码
        String projectCode = request.getHeader(QCAuthConstant.PROJECT_CODE_HEADER_KEY);

        return uacService.getUacUserInfoByToken(token, projectCode);
    }

    @RequestMapping(value = "/modifypwd", method = {RequestMethod.GET, RequestMethod.POST})
    public String modifyPassword(@RequestBody UserModifyPasswordDto dto) throws QCPromptException, QcTokenInvalidException {
        //权限验证需要token，获取token
        String token = request.getHeader(QCAuthConstant.TOKEN_HEADER_KEY);

        return uacService.modifyUserPassword(token, dto);
    }

    @GetMapping("/logout")
    public String logout() {
        //在此可以获取客户端userAgent，退出登录时可以将同类型客户端所有登录记录均设置为过期，避免token重复使用

        //权限验证需要token，获取token
        String token = request.getHeader(QCAuthConstant.TOKEN_HEADER_KEY);

        return uacService.logout(token);
    }

    /***
     * 获取菜单列表，根据登录用户token和指定的项目编码
     *
     * @param id 项目编码
     * @return java.util.List<qc.module.platform.dto.uac.UacMenuDto>
     * @author QuCheng Tech
     * @since 2023/8/15
     */
    @GetMapping(value = "/menuList/{id}")
    public List<UacRouteDto> getMenuListByPath(@PathVariable(required = true) String id) throws QCPromptException, QcTokenInvalidException {
        //权限验证需要token，获取token
        String token = request.getHeader(QCAuthConstant.TOKEN_HEADER_KEY);

        return uacService.getProjectValidMenus(token, id);
    }

    /***
     * 获取菜单列表，根据登录用户token和指定的项目编码
     *
     * @param id 项目编码
     * @return java.util.List<qc.module.platform.dto.uac.UacMenuDto>
     * @author QuCheng Tech
     * @since 2023/8/15
     */
    @GetMapping(value = "/menuList")
    public List<UacRouteDto> getMenuListByParam(@RequestParam(required = true) String id) throws QCPromptException, QcTokenInvalidException {
        //权限验证需要token，获取token
        String token = request.getHeader(QCAuthConstant.TOKEN_HEADER_KEY);

        return uacService.getProjectValidMenus(token, id);
    }

    /**
     * 根据输入的Integer值获取对应的身份验证方式枚举
     *
     * @param index
     * @return qc.common.core.enums.QCAuthValidateMethodEnum
     * @author QuCheng Tech
     * @date 2023/1/11
     */
    static QCAuthValidateMethodEnum getQCAuthValidateMethodEnum(Integer index) {
        if (index != null && index > 0x0) {
            for (QCAuthValidateMethodEnum item : QCAuthValidateMethodEnum.values()) {
                if (item.getIndex() == index) {//判断序号使用getIndex，判断内容使用getName
                    return item;
                }
            }
        }
        return QCAuthValidateMethodEnum.PWD;
    }
}
